﻿using System;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Text.RegularExpressions;
using System.Text;

namespace Mytrip.Users
{
    public class MembershipRepository : MembershipProvider
    {
        usersEntities _db = new usersEntities(UsersSetting.connectionString);
        public override string ApplicationName
        {
            get
            {
                return UsersSetting.applicationName;
            }
            set { UsersSetting.applicationName = value; }
        }
        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            bool result = false;
            var user = _GetMembership(username);
            if (user != null && _TransformPassword(oldPassword, user.PasswordSalt) == user.Password)
            {
                string newGuid = Guid.NewGuid().ToString();
                mytrip_Membership x = user;
                x.Password = _TransformPassword(newPassword, newGuid);
                x.PasswordSalt = newGuid;
                x.LastPasswordChangedDate = DateTime.Now;
                _db.SaveChanges();
                result = true;
            }
            return result;
        }
        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {

            return false;
        }
        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            if (!_AccessibleUserName(username))
                status = MembershipCreateStatus.DuplicateUserName;
            if (String.IsNullOrEmpty(username))
                status = MembershipCreateStatus.InvalidUserName;
            if (String.IsNullOrEmpty(password))
                status = MembershipCreateStatus.InvalidPassword;
            if (password.Length < UsersSetting.minRequiredPasswordLength)
                status = MembershipCreateStatus.InvalidPassword;
            if (RequiresUniqueEmail && !_AccessibleEmail(email))
                status = MembershipCreateStatus.DuplicateEmail;
            if (String.IsNullOrEmpty(email))
                status = MembershipCreateStatus.InvalidEmail;
            if (!Regex.IsMatch(email, "^[a-z0-9_\\+-]+(\\.[a-z0-9_\\+-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*\\.([a-z]{2,4})$"))
                status = MembershipCreateStatus.InvalidEmail;
            string userId = _UserId();
            _CreateUser(userId, username);
            _CreateMembership(userId, password, email, isApproved);
            status = MembershipCreateStatus.Success;
            var user = _GetUser(username);
            return CreateMembershipFromInternalUser(user);
        }
        private MembershipUser CreateMembershipFromInternalUser(mytrip_Users user)
        {
            MembershipUser muser = new MembershipUser(base.Name, user.UserName, user.UserId,
                user.mytrip_Membership.Email, string.Empty, string.Empty, user.mytrip_Membership.IsApproved, false,
                user.mytrip_Membership.CreationDate, user.mytrip_Membership.LastLoginDate, user.LastActivityDate, user.mytrip_Membership.LastPasswordChangedDate,
                user.mytrip_Membership.LastLockoutDate);
            return muser;
        }
        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            bool result = false;
            var user = _GetUser(username);
            if (user != null)
            {
                _RemoveUserFromRoles(username);
                _DeleteMembership(username);
                mytrip_Users x = user;
                _db.DeleteObject(x);
                _db.SaveChanges();
                result = true;
            }
            return result;
        }
        public override bool EnablePasswordReset
        {
            get
            {
                return true;
            }
        }
        public override bool EnablePasswordRetrieval
        {
            get
            {
                return false;
            }
        }
        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            var users = _db.mytrip_Users.Where(x => x.mytrip_Membership.Email.IndexOf(emailToMatch) != -1)
                .OrderByDescending(x => x.LastActivityDate)
                .Skip((pageIndex - 1) * pageSize).Take(pageSize);
            totalRecords = _db.mytrip_Users.Where(x => x.mytrip_Membership.Email.IndexOf(emailToMatch) != -1)
                .OrderByDescending(x => x.LastActivityDate).Count();
            return CreateMembershipCollectionFromInternalList(users);
        }
        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            var users = _db.mytrip_Users.Where(x => x.UserName.IndexOf(usernameToMatch) != -1)
                .OrderByDescending(x => x.LastActivityDate)
                .Skip((pageIndex - 1) * pageSize).Take(pageSize);
            totalRecords = _db.mytrip_Users.Where(x => x.UserName.IndexOf(usernameToMatch) != -1)
                .OrderByDescending(x => x.LastActivityDate).Count();
            return CreateMembershipCollectionFromInternalList(users);
        }
        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            var users = _db.mytrip_Users.OrderByDescending(x => x.LastActivityDate)
                .Skip((pageIndex - 1) * pageSize).Take(pageSize);
            totalRecords = _db.mytrip_Users.OrderByDescending(x => x.LastActivityDate).Count();
            return CreateMembershipCollectionFromInternalList(users);
        }
        private MembershipUserCollection CreateMembershipCollectionFromInternalList(IQueryable<mytrip_Users> users)
        {
            MembershipUserCollection ReturnCollection = new MembershipUserCollection();
            foreach (mytrip_Users user in users)
            {
                ReturnCollection.Add(CreateMembershipFromInternalUser(user));
            }
            return ReturnCollection;
        }
        public override int GetNumberOfUsersOnline()
        {
            var users = _db.mytrip_Users.OrderByDescending(x => x.LastActivityDate);
            int result = 0;
            foreach (mytrip_Users user in users)
            {
                if (user.LastActivityDate.AddMinutes(Membership.UserIsOnlineTimeWindow) >= DateTime.Now)
                {
                    result++;
                }
            }
            return result;
        }
        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }
        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            var user = _GetUserId(username);
            if (user != null)
            {
                if (userIsOnline)
                {
                    _LastActivityDate(username);
                }
                return CreateMembershipFromInternalUser(user);
            }
            else
            {
                return null;
            }
        }
        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            var user = _GetUserId(providerUserKey.ToString());
            if (user != null)
            {
                if (userIsOnline)
                {
                    _LastActivityDate(user.UserName);
                }
                return CreateMembershipFromInternalUser(user);
            }
            else
            {
                return null;
            }
        }
        public override string GetUserNameByEmail(string email)
        {
            string result = string.Empty;
            var user = _db.mytrip_Users.FirstOrDefault(x => x.mytrip_Membership.Email == email);
            if (user != null)
                result = user.UserName;
            return result;
        }
        public override int MaxInvalidPasswordAttempts
        {
            get
            {
                return UsersSetting.maxInvalidPasswordAttempts;
            }
        }
        public override int MinRequiredNonAlphanumericCharacters
        {
            get
            {
                return 0;
            }
        }
        public override int MinRequiredPasswordLength
        {
            get
            {
                return UsersSetting.minRequiredPasswordLength;
            }
        }
        public override int PasswordAttemptWindow
        {
            get
            {
                return 10;
            }
        }
        public override MembershipPasswordFormat PasswordFormat
        {
            get { return MembershipPasswordFormat.Hashed; }
        }
        public override string PasswordStrengthRegularExpression
        {
            get { return string.Empty; }
        }
        public override bool RequiresQuestionAndAnswer
        {
            get { return false; }
        }
        public override bool RequiresUniqueEmail
        {
            get
            {
                return UsersSetting.requiresUniqueEmail;
            }
        }
        public override string ResetPassword(string username, string answer)
        {
            return string.Empty;
        }
        public override bool UnlockUser(string userName)
        {
            bool result = false;
            var user = _db.mytrip_Membership.FirstOrDefault(x=>x.mytrip_Users.UserName==userName);
            if (user != null)
            {
                mytrip_Membership x = user;
                if (user.IsApproved)
                {
                    x.IsApproved = false;
                }
                else
                {
                    x.IsApproved = true;
                }
                _db.SaveChanges();
                result = true;
            }
            return result;
        }
        public override void UpdateUser(MembershipUser user)
        {

        }
        public override bool ValidateUser(string username, string password)
        {
            bool result = false;
            if (_LogonUserName(username))
            {
                var user = _GetMembership(username);
                if (user != null && _TransformPassword(password, user.PasswordSalt) == user.Password)
                {
                    _UpdateUserIP(username);
                    result = true;
                }
            }
            return result;
        }
        /*  ----------------------------------------------------------*/
        #region получить пользователя по Id
        private mytrip_Users _GetUserId(string userid)
        {
            return _db.mytrip_Users.FirstOrDefault(x => x.UserId == userid);
        }
        #endregion
        #region создать уникальный UserId
        private string _UserId()
        {
            string result = Guid.NewGuid().ToString();
            while (_GetUserId(result) != null)
            {
                result = Guid.NewGuid().ToString();
            }
            return result;
        }
        #endregion
        #region получить пользователя по имени
        public mytrip_Users _GetUser(string username)
        {
            return _db.mytrip_Users.FirstOrDefault(x => x.UserName == username);
           
        }
        #endregion
        #region получить пользователя по имени
        public mytrip_Users _GetUserandEmail(string username)
        {
            var user = _db.mytrip_Users.FirstOrDefault(x => x.UserName == username);
            if (user == null)
                user = _db.mytrip_Users.FirstOrDefault(x => x.mytrip_Membership.Email == username);
            return user;
        }
        #endregion
        #region создать пользователя
        private void _CreateUser(string userId, string userName)
        {
            mytrip_Users x = new mytrip_Users
            {
                UserId = userId,
                UserName = userName,
                LastActivityDate = DateTime.Now
            };
            _db.AddTomytrip_Users(x);
            _db.SaveChanges();
        }
        #endregion
        #region создать membership пользователя
        private void _CreateMembership(string userId, string password, string email, bool isApproved)
        {
            string newGuid = Guid.NewGuid().ToString();
            mytrip_Membership x = new mytrip_Membership
            {
                UserId = userId,
                Password = _TransformPassword(password, newGuid),
                PasswordSalt = newGuid,
                Email = email,
                IsApproved = isApproved,
                CreationDate = DateTime.Now,
                LastLockoutDate = DateTime.MaxValue,
                LastLoginDate = DateTime.Now,
                LastPasswordChangedDate = DateTime.Now,
                UserIP = HttpContext.Current.Request.UserHostAddress
            };
            _db.AddTomytrip_Membership(x);
            _db.SaveChanges();
        }
        #endregion
        #region зашифровать пароль
        private string _TransformPassword(string password,
                                         string passwordsalt)
        {
            string c = FormsAuthentication
                .HashPasswordForStoringInConfigFile((passwordsalt + password), "SHA1");
            return c;
        }
        #endregion
        #region получить мембершип пользователя
        private mytrip_Membership _GetMembership(string username)
        {
            string userId = _userId(username);
            return _db.mytrip_Membership.FirstOrDefault(x => x.UserId == userId);
        }
        #endregion
        #region получить Id пользователя
        private string _userId(string username)
        {
            return _GetUser(username).UserId;
        }
        #endregion
        #region удалить роли пользователя
        private void _RemoveUserFromRoles(string username)
        {
            var user = _GetUser(username);
            if (user.mytrip_Roles != null)
            {
                foreach (mytrip_Roles x in user.mytrip_Roles.ToList())
                {
                    var role = _GetRole(x.RoleName);
                    user.mytrip_Roles.Remove(role);
                    _db.SaveChanges();
                }
            }
        }
        #endregion
        #region получить роль по имени
        private mytrip_Roles _GetRole(string rolename)
        {
            return _db.mytrip_Roles.FirstOrDefault(x => x.RoleName == rolename);
        }
        #endregion
        #region удалить мембершип пользователя
        private void _DeleteMembership(string username)
        {
            mytrip_Membership x = _db.mytrip_Membership.FirstOrDefault(y=>y.mytrip_Users.UserName==username);
            _db.DeleteObject(x);
            _db.SaveChanges();
        }
        #endregion
        #region обновить дату online
        public void _LastActivityDate(string username)
        {
            mytrip_Users x = _GetUser(username);
            x.LastActivityDate = DateTime.Now;
            _db.SaveChanges();
        }
        #endregion
        #region обновить IP при входе
        private void _UpdateUserIP(string username)
        {
            mytrip_Membership x = _GetMembership(username);
            x.UserIP = HttpContext.Current.Request.UserHostAddress;
            _db.SaveChanges();
        }
        #endregion
        /*-------------------------------------------------------------------------*/
        #region проверить имя пользователя на доступность
        public bool _AccessibleUserName(string username)
        {
            bool result = true;
            var _users = _GetUser(username);
            if (_users != null)
                result = false;          
            return result;
        }
        #endregion
        #region проверить email на доступность
        public bool _AccessibleEmail(string email)
        {
            bool result = true;
            var _users = _db.mytrip_Membership.FirstOrDefault(x => x.Email == email);
            if (_users != null)
                result = false;
            return result;
        }
        #endregion
        #region проверить имя пользователя при входе
        public bool _LogonUserName(string username)
        {
            bool result = false;
            var users = _GetUser(username);
            if (users != null)
            {
                bool _users = users.mytrip_Membership.IsApproved;
                if (_users)
                    result = true;
            }
            return result;
        }
        #endregion
        #region проверить старый пароль при смене пароля
        public bool _CurrentPassword(string password)
        {
            bool result = false;
            var user = _GetMembership(HttpContext.Current.User.Identity.Name);
            if (user != null && _TransformPassword(password, user.PasswordSalt) == user.Password)
            {
                result = true;
            }
            return result;
        }
        #endregion
        /*-------------------------------------------------------------------------*/
        #region получить всех пользователей постранично с сортировкой
        public IQueryable<mytrip_Users> AdminGetAllUsers(int pageIndex, int pageSize, string sort, out int total)
        {    
            total = _db.mytrip_Users.OrderByDescending(x => x.LastActivityDate).Count();
            var users = _db.mytrip_Users.OrderByDescending(x => x.LastActivityDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);            
            if (sort == "UserName")
                users = _db.mytrip_Users.OrderBy(x => x.UserName).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "_UserName")
                users = _db.mytrip_Users.OrderByDescending(x => x.UserName).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "Email")
                users = _db.mytrip_Users.OrderBy(x => x.mytrip_Membership.Email).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "_Email")
                users = _db.mytrip_Users.OrderByDescending(x => x.mytrip_Membership.Email).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "LastActivityDate")
                users = _db.mytrip_Users.OrderBy(x => x.LastActivityDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "_LastActivityDate")
                users = _db.mytrip_Users.OrderByDescending(x => x.LastActivityDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "CreationDate")
                users = _db.mytrip_Users.OrderBy(x => x.mytrip_Membership.CreationDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "_CreationDate")
                users = _db.mytrip_Users.OrderByDescending(x => x.mytrip_Membership.CreationDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "LastLoginDate")
                users = _db.mytrip_Users.OrderBy(x => x.mytrip_Membership.LastLoginDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "_LastLoginDate")
                users = _db.mytrip_Users.OrderByDescending(x => x.mytrip_Membership.LastLoginDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "LastPasswordChangedDate")
                users = _db.mytrip_Users.OrderBy(x => x.mytrip_Membership.LastPasswordChangedDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "_LastPasswordChangedDate")
                users = _db.mytrip_Users.OrderByDescending(x => x.mytrip_Membership.LastPasswordChangedDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "UserIP")
                users = _db.mytrip_Users.OrderBy(x => x.mytrip_Membership.UserIP).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (sort == "_UserIP")
                users = _db.mytrip_Users.OrderByDescending(x => x.mytrip_Membership.UserIP).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            if (!String.IsNullOrEmpty(sort) && sort != "UserName" && sort != "_UserName" && sort != "Email" && sort != "_Email"
                && sort != "LastActivityDate" && sort != "_LastActivityDate" && sort != "CreationDate" && sort != "_CreationDate"
                && sort != "LastLoginDate" && sort != "_LastLoginDate" && sort != "LastPasswordChangedDate" 
                && sort != "_LastPasswordChangedDate"
                && sort != "UserIP" && sort != "_UserIP") {
                    var user = _db.mytrip_Users.Where(x => x.UserName.IndexOf(sort) != -1);
                    var _user = _db.mytrip_Users.Where(x => x.mytrip_Membership.Email.IndexOf(sort) != -1);
                    total = user.Union(_user).Count();
                    users = user.Union(_user).OrderBy(x => x.UserName).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            }
            return users;
        }
        #endregion
        #region удалить пользователя
        public void _DeleteUser(string username)
        {
            var user = _GetUser(username);
            if (user != null)
            {
                _RemoveUserFromRoles(username);
                _DeleteMembership(username);
                mytrip_Users x = user;
                _db.DeleteObject(x);
                _db.SaveChanges();
            }
        }
        #endregion
        public string _GetSearchUsers(string search)
        {
            var user = _db.mytrip_Users.Where(x => x.UserName.IndexOf(search) != -1);
           //var _user = _db.mytrip_Users.Where(x => x.mytrip_Membership.Email.IndexOf(search) != -1);
           //users = user.Union(_user);
            StringBuilder result = new StringBuilder();
            foreach (mytrip_Users item in user)
            {
                result.AppendLine(item.UserName);
               // result.AppendLine(item.mytrip_Membership.Email);
            }
            return result.ToString();
        }
        public string _TransformCaptcha(string password)
        {
            string c = FormsAuthentication
                .HashPasswordForStoringInConfigFile((UsersSetting.connectionStringName + password), "SHA1");
            return c;
        }
    }
}